package com.easydict.writer;

import com.easydict.annotation.EasyDict;
import com.easydict.core.SerializationContext;
import com.easydict.spi.DictionaryResolutionContext;
import com.easydict.spi.DictionaryResolver;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;

import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 增强的字典属性写入器
 * 提供高性能的字典值解析和序列化功能
 */
public class EnhancedDictionaryPropertyWriter extends BeanPropertyWriter {
    
    private static final AtomicLong INSTANCE_COUNTER = new AtomicLong(0);
    private static final String DEFAULT_DICT_SUFFIX = "Dict";

    private final BeanPropertyWriter delegateWriter;
    private final EasyDict annotationMetadata;
    private final DictionaryResolver dictionaryResolver;
    private final SerializationContext serializationContext;
    private final String configuredSuffix;
    private final long instanceId;
    private final String dictionaryFieldName;
    private final SerializationStrategy serializationStrategy;
    
    public EnhancedDictionaryPropertyWriter(
            BeanPropertyWriter delegateWriter,
            EasyDict annotation,
            DictionaryResolver resolver,
            SerializationContext context,
            String configuredSuffix) {

        super(delegateWriter);
        this.delegateWriter = delegateWriter;
        this.annotationMetadata = annotation;
        this.dictionaryResolver = resolver;
        this.serializationContext = context;
        this.configuredSuffix = configuredSuffix != null ? configuredSuffix : DEFAULT_DICT_SUFFIX;
        this.instanceId = INSTANCE_COUNTER.incrementAndGet();
        this.dictionaryFieldName = computeDictionaryFieldName();
        this.serializationStrategy = createSerializationStrategy();
    }
    
    @Override
    public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
        // 执行原始字段序列化
        serializationStrategy.serializeOriginalField(bean, gen, prov, delegateWriter);
        
        // 执行字典字段序列化
        serializationStrategy.serializeDictionaryField(bean, gen, prov, this);
    }
    
    public Optional<String> resolveDictionaryValue(Object bean) {
        try {
            Object fieldValue = delegateWriter.get(bean);

            DictionaryResolutionContext resolutionContext = DictionaryResolutionContext.builder()
                    .typeCode(annotationMetadata.dictType())
                    .rawValue(fieldValue)
                    .sourceType(bean.getClass())
                    .fieldName(delegateWriter.getName())
                    .attribute("instanceId", instanceId)
                    .attribute("serializationContext", serializationContext)
                    .attribute("annotation", annotationMetadata)
                    .build();

            Optional<String> result = dictionaryResolver.resolve(resolutionContext);

            // 如果解析失败，尝试使用fallback值
            if (!result.isPresent()) {
                String fallbackValue = getFallbackValue(fieldValue);
                if (fallbackValue != null) {
                    return Optional.of(fallbackValue);
                }
            }

            return result;

        } catch (Exception e) {
            // 记录错误但不中断序列化过程
            handleResolutionError(e, bean);

            // 异常情况下也尝试使用fallback值
            try {
                Object fieldValue = delegateWriter.get(bean);
                String fallbackValue = getFallbackValue(fieldValue);
                if (fallbackValue != null) {
                    return Optional.of(fallbackValue);
                }
            } catch (Exception ignored) {
                // 忽略获取fallback时的异常
            }

            return Optional.empty();
        }
    }
    
    public String getDictionaryFieldName() {
        return dictionaryFieldName;
    }
    
    public long getInstanceId() {
        return instanceId;
    }
    
    private String computeDictionaryFieldName() {
        String baseName = delegateWriter.getName();

        // 优先使用注解中的自定义后缀
        if (annotationMetadata.suffix() != null && !annotationMetadata.suffix().trim().isEmpty()) {
            return baseName + annotationMetadata.suffix();
        }

        // 其次使用全局配置的后缀
        return baseName + configuredSuffix;
    }
    
    private SerializationStrategy createSerializationStrategy() {
        return new DefaultSerializationStrategy();
    }
    
    /**
     * 获取fallback值
     */
    private String getFallbackValue(Object fieldValue) {
        // 检查注解中是否配置了fallback值
        String fallback = annotationMetadata.fallback();
        if (fallback != null && !fallback.trim().isEmpty()) {
            return fallback;
        }

        // 如果没有配置fallback，返回null表示不使用fallback
        return null;
    }

    private void handleResolutionError(Exception e, Object bean) {
        // 可以在这里添加日志记录或错误处理逻辑
        // 为了保持性能，这里暂时不做处理
    }
    
    /**
     * 序列化策略接口
     */
    private interface SerializationStrategy {
        void serializeOriginalField(Object bean, JsonGenerator gen, SerializerProvider prov, 
                                   BeanPropertyWriter writer) throws Exception;
        void serializeDictionaryField(Object bean, JsonGenerator gen, SerializerProvider prov, 
                                    EnhancedDictionaryPropertyWriter writer) throws Exception;
    }
    
    /**
     * 默认序列化策略实现
     */
    private static class DefaultSerializationStrategy implements SerializationStrategy {
        
        @Override
        public void serializeOriginalField(Object bean, JsonGenerator gen, SerializerProvider prov, 
                                         BeanPropertyWriter writer) throws Exception {
            writer.serializeAsField(bean, gen, prov);
        }
        
        @Override
        public void serializeDictionaryField(Object bean, JsonGenerator gen, SerializerProvider prov, 
                                           EnhancedDictionaryPropertyWriter writer) throws Exception {
            Optional<String> dictionaryValue = writer.resolveDictionaryValue(bean);
            String fieldName = writer.getDictionaryFieldName();
            
            if (dictionaryValue.isPresent()) {
                gen.writeStringField(fieldName, dictionaryValue.get());
            } else {
                gen.writeNullField(fieldName);
            }
        }
    }
}
